<?php

namespace app\admin\controller;

use app\common\controller\Backend;
use app\common\model\Refund as RefundModel;
use think\Db;
use think\exception\PDOException;
use think\exception\ValidateException;
use Exception;

/**
 * 退款管理
 *
 * @icon fa fa-money
 */
class Refund extends Backend
{
    
    /**
     * Refund模型对象
     * @var \app\common\model\Refund
     */
    protected $model = null;

    public function _initialize()
    {
        parent::_initialize();
        $this->model = new RefundModel;
    }
    
    /**
     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法
     * 因此在当前控制器中可不用编写增删改查的代码
     */
    
    /**
     * 查看
     */
    public function index()
    {
        //当前是否为关联查询
        $this->relationSearch = true;
        //设置过滤方法
        $this->request->filter(['strip_tags', 'trim']);
        if ($this->request->isAjax()) {
            //如果发送的来源是Selectpage，则转发到Selectpage
            if ($this->request->request('keyField')) {
                return $this->selectpage();
            }
            list($where, $sort, $order, $offset, $limit) = $this->buildparams();
            $list = $this->model
                    ->with(['user', 'order', 'applyItem'])
                    ->where($where)
                    ->order($sort, $order)
                    ->paginate($limit);

            $result = array("total" => $list->total(), "rows" => $list->items());

            return json($result);
        }
        return $this->view->fetch();
    }
    
    /**
     * 详情
     */
    public function detail($ids = null)
    {
        $row = $this->model->get($ids);
        if (!$row) {
            $this->error(__('No Results were found'));
        }
        
        // 关联查询
        $row->user;
        $row->order;
        $row->applyItem;
        
        $this->view->assign("row", $row);
        return $this->view->fetch();
    }
    
    /**
     * 同步退款状态
     */
    public function sync($ids = null)
    {
        $row = $this->model->get($ids);
        if (!$row) {
            $this->error(__('No Results were found'));
        }
        
        if ($row['status'] == 1) {
            $this->error('退款已成功，无需同步');
        }
        
        try {
            // 加载微信支付配置
            $config = \think\Config::get('wechat.pay');
            if (empty($config)) {
                throw new Exception('微信支付配置未找到');
            }
            
            // 修复证书路径配置
            if (empty($config['key_path']) && !empty($config['merchant_private_key_path'])) {
                $config['key_path'] = $config['merchant_private_key_path'];
            }
            
            // 确保证书路径正确
            if (!empty($config['key_path'])) {
                // 处理$_SERVER['DOCUMENT_ROOT']变量
                if (strpos($config['key_path'], '$$_SERVER') !== false) {
                    $config['key_path'] = str_replace('$$_SERVER[\'DOCUMENT_ROOT\']', $_SERVER['DOCUMENT_ROOT'], $config['key_path']);
                } elseif (strpos($config['key_path'], '$_SERVER') !== false) {
                    $config['key_path'] = str_replace('$_SERVER[\'DOCUMENT_ROOT\']', $_SERVER['DOCUMENT_ROOT'], $config['key_path']);
                }
                
                // 如果是相对路径，转换为绝对路径
                if (strpos($config['key_path'], ':') === false && substr($config['key_path'], 0, 1) !== '/') {
                    // 检查几种可能的路径
                    $possiblePaths = [
                        $_SERVER['DOCUMENT_ROOT'] . '/wxcert/apiclient_key.pem',
                        $_SERVER['DOCUMENT_ROOT'] . '/public/wxcert/apiclient_key.pem',
                        ROOT_PATH . 'public/wxcert/apiclient_key.pem',
                        ROOT_PATH . 'wxcert/apiclient_key.pem'
                    ];
                    
                    foreach ($possiblePaths as $path) {
                        if (file_exists($path)) {
                            $config['key_path'] = $path;
                            break;
                        }
                    }
                }
            }
            
            // 查询退款状态
            $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/' . $row['refund_no'];
            
            $result = $this->requestWechatRefundQuery('GET', $url, $config);
            
            if (isset($result['status'])) {
                $status = 0; // 默认处理中
                if ($result['status'] === 'SUCCESS') {
                    $status = 1; // 成功
                } else if ($result['status'] === 'FAIL') {
                    $status = 2; // 失败
                }
                
                $updateData = [
                    'status' => $status,
                    'update_time' => time()
                ];
                
                if ($status == 2 && isset($result['reason'])) {
                    $updateData['fail_reason'] = $result['reason'];
                }
                
                $this->model->where('id', $ids)->update($updateData);
                
                $this->success('同步成功');
            } else {
                $this->error('同步失败：' . ($result['message'] ?? '未知错误'));
            }
            
        } catch (Exception $e) {
            $this->error('同步失败：' . $e->getMessage());
        }
    }
    
    /**
     * 发送微信退款查询请求
     * 
     * @param string $method HTTP方法
     * @param string $url 请求URL
     * @param array $config 微信支付配置
     * @return array 响应结果
     */
    private function requestWechatRefundQuery($method, $url, $config) {
        $body = '';
        $auth = $this->buildRefundAuth($method, $url, $body, $config);
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER => [
                'Accept: application/json',
                'Content-Type: application/json',
                'User-Agent: FastAdmin/WeChatPay',
                'Authorization: ' . $auth
            ]
        ]);
        
        $response = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            throw new Exception("CURL Error: " . $error);
        }
        
        $result = json_decode($response, true);
        
        if ($status !== 200) {
            $message = isset($result['message']) ? $result['message'] : '微信退款查询接口请求失败';
            $code = isset($result['code']) ? $result['code'] : 'UNKNOWN_ERROR';
            throw new Exception("[$code] $message");
        }
        
        return $result;
    }
    
    /**
     * 构造退款请求的Authorization
     * 
     * @param string $method HTTP方法
     * @param string $url 请求URL
     * @param string $body 请求体
     * @param array $config 微信支付配置
     * @return string Authorization头
     */
    private function buildRefundAuth($method, $url, $body, $config) {
        $timestamp = time();
        $nonce = uniqid();
        $urlParts = parse_url($url);
        $canonicalUrl = ($urlParts['path'] ?? '/') . (isset($urlParts['query']) ? '?' . $urlParts['query'] : '');
        
        $message = $method . "\n" .
            $canonicalUrl . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
        
        $signature = $this->generateRefundSign($message, $config['key_path']);
        
        return sprintf(
            'WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $config['mchid'],
            $nonce,
            $timestamp,
            $config['serial_no'],
            $signature
        );
    }
    
    /**
     * 生成退款请求签名
     * 
     * @param string $message 签名串
     * @param string $keyPath 商户API私钥路径
     * @return string 签名
     */
    private function generateRefundSign($message, $keyPath) {
        $privateKey = openssl_pkey_get_private(file_get_contents($keyPath));
        if (!$privateKey) {
            throw new Exception('无法加载商户API私钥');
        }
        
        $signature = '';
        if (!openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
            openssl_free_key($privateKey);
            throw new Exception('签名生成失败: ' . openssl_error_string());
        }
        
        openssl_free_key($privateKey);
        return base64_encode($signature);
    }
}